#
# $Id: helper.inc 40 2015-08-06 12:44:34Z chupin007@gmail.com $
# $HeadURL: http://bapps.googlecode.com/svn/trunk/lib/helper.inc $
#
set -e

if [ "$common_loaded" = "Y" ]; then
  echo "common.func has been already loaded."
  exit 1
fi
common_LOGLEVEL=0
common_loaded="N"
common_NOLF="N"
common_CONSOLEOUTPUT="N"
common_KEEPTEMPFILE="N"
common_EMAILADDR=""
common_PRINTCALLSTACK="Y"
common_INERRPROCESSING=N
declare -a common_onExitFunc

common_CONSOLEOUTPUT="Y"

# usage: Log [-l loglevel] [-n] [-e] [-D] [-f filename] message
# -l loglevel - log level
# -n          - no line feed
# -e          - enable interpretation of backslash escapes
# -D          - no date at begin of log line
# -C          - no console output
# -f filename - write message to specified log file
Log() {
  local OPT OPTIND=1 OPTARG msglevel echoopt msglevel logfilename nodate linestart nolf logspace="common" global_NOLF auxfilename="N" ti
  local enableconsole;
  logfilename="$LOGFILENAME"
  msglevel=0
  echoopt=""
  nodate="N"
  nolf="N"
  while getopts l:N:neDCf: OPT
  do
    case $OPT in
      "l" ) msglevel="$OPTARG" ;;
      "n" ) echoopt="$echoopt -n"; nolf="Y" ;;
      "e" ) echoopt="$echoopt -e" ;;
      "D" ) nodate="Y" ;;
      "N" ) logspace="$OPTARG" ;;
      "C" ) enableconsole="N"; ;;
      "f" ) logfilename="$OPTARG"; auxfilename="Y" ;;
       *  ) echo "wrong opttion $OPT"; return 1 ;;
    esac
  done
  shift $(($OPTIND-1))

  if [ -z "$enableconsole" ]; then
    eval enableconsole=\$${logspace}_CONSOLEOUTPUT
  fi
  if [ "$logspace" = "common" ] && [ ! "$common_loaded" = "Y" ]; then enableconsole="Y"; fi

  if [ "$logspace" = "common" ]; then
    logfilename="$LOGFILENAME"
  fi
  if [ "$msglevel" -ge 0 ]; then msglevel=$msglevel; else msglevel=0; fi 2>/dev/null
  eval global_NOLF=\$${logspace}_NOLF
  if [ -z "$common_LOGLEVEL" ] || [ $msglevel -le $common_LOGLEVEL ]; then
    if [ "$nodate" = "N" ]; then
      if [ "$global_NOLF" = "Y" ]; then
         if [ "$enableconsole" = "Y" ]; then
           echo;
         fi
         if [ "$common_loaded" = "Y" ] && [ ! -z "$logfilename" ]; then
           echo >> $logfilename;
         fi
      fi
      ti=`date +%Y-%m-%d:%H:%M:%S.%N`
      ti=${ti:0:${#ti}-3}
      linestart="$ti "
    else
      linestart=""
    fi
    if [ "$enableconsole" = "Y" ]; then
      echo $echoopt "$linestart$@"
    fi
    if [ "$common_loaded" = "Y" ] && [ ! -z "$logfilename" ]; then
      echo $echoopt "$linestart$@" >> $logfilename
    fi
#    common_NOLF=$nolf
     eval ${logspace}_NOLF=\$nolf
  fi
}

Write() {
  Log -D "$@"
}

WriteNoLF() {
  Log -D -n "$@"
}

WriteLF() {
  Log -D "$@"
}

enableConsoleOutput() {
  common_CONSOLEOUTPUT="Y"
}

disableConsoleOutput() {
  common_CONSOLEOUTPUT="N"
}

enable_PrintCallStack() {
  common_PRINTCALLSTACK="Y"
}

disable_PrintCallStack() {
  common_PRINTCALLSTACK="N"
}

common_PrintCallStack() {
  if [ "$common_loaded" = "Y" ] && [ "$common_PRINTCALLSTACK" = "Y" ] ; then
    local dumpfile
    Log "   Line : Function"
    Log "==================="
    for((i=${#BASH_SOURCE[*]}-1;i>0;i--))
    do
      if [ $i -gt 0 ]; then
        lineno=${BASH_LINENO[$i-1]}
      else
        linno=$LINENO
      fi
  #    Log "`printf \"%7s : %s\n\" \"$lineno\" \"${FUNCNAME[$i]} (${BASH_SOURCE[$i]})\"`"
      Log "`printf \"%7s : %s\n\" \"$lineno\" \"${FUNCNAME[$i]} (${BASH_SOURCE[$i]})\"`"
    done
    dumpfile=$APPPATH/$SCRIPTNAME.dump.`date +%Y%m%d%H%M%S`
    Log "env vars saved as $dumpfile"
    set >$dumpfile
  fi
}

Err() {
  local i linno
  if [ "$common_INERRPROCESSING" = "N" ]; then
    common_INERRPROCESSING=Y
    Log "ERROR: $@"
    if [ "$common_PRINTCALLSTACK" = "Y" ]; then
      common_PrintCallStack
      common_PRINTCALLSTACK="N"
    fi
    if [ "$common_notifyOnAbort" = "Y" ] || [ "$common_notifyOnStop" = "Y" ]; then
      alertemail "$PROCDESCR exited with RC=1."
      common_notifyOnAbort=N
      common_notifyOnStop=N
    fi
  fi
  exit 1
}

UsageAndExit() {
  usage
  Err "$@"
}

LogIfErr() {
  local rc=$?
#  if [ $rc -ne 0 ] && [ "$common_StopOnError" = "Y" ]; then Log "$@"; fi
  if [ $rc -ne 0 ]; then Log "$@"; fi
  return $rc
}

LogOnErr() {
#  if [ "$common_StopOnError" = "Y" ]; then Log "$@"; fi
  Log "$@";
  return 1;
}

ExitIfErr() {
  local rc=$?
  if [ $rc -ne 0 ]; then Err "$@, (RC=$rc)"; fi
}

LogStart() {
  Log "Started with command line: $common_COMMANDLINEPARAMS"
  common_STARTSTOPMSG="Y"
}

LogStop() {
  local rc=$1
  if [ $rc -eq 0 ]; then
    Log "competed succsessfully"
  else
    Log "FAILURE: $APPPATH/$PROCNAME complited with status $rc"
  fi
}

LogBEGIN() {
  startTimer common_BEGINENDTIME
  Log -n "$@"...
}

LogEND() {
  local timediff
  readTimer common_BEGINENDTIME timediff
  Write "$@" "ok, time=$timediff"
}

common_StopOnError=Y
enableStopOnError() {
  common_StopOnError=Y
}
disableStopOnError() {
  common_StopOnError=N
}
unalias -a
ExitIfErr "cannot remove all aliases"
alias returnOnError='common_AppsReturnIfErr=$?; (( ! $common_AppsReturnIfErr )) || return $common_AppsReturnIfErr'
alias ifErrorInFunction='common_AppsReturnIfErr=$?; (( ! $common_AppsReturnIfErr )) || if [ "$common_StopOnError" = "Y" ]; then Err "error in function."; else return $common_AppsReturnIfErr; fi'
alias onErrorInFunction='if [ "$common_StopOnError" = "Y" ]; then Err "error in function."; else return 1; fi'
alias continueOnError='common_AppsCommonIfErr=$?; (( ! $common_AppsCommonIfErr )) || continue'
shopt -s expand_aliases

# Usage: normalizePath PATHVARNAME
normalizePath() {
  local pathvn="$1"; local trim; local flag; local token; local changemade; local realpath
  local path=${!pathvn}
  if [ -z "$path" ]; then
    LogOnErr "normalizePath: empty path passed in $pathvn variable"; onErrorInFunction
  fi
  if [ "${path:0:1}" != "/" ]; then path="$PWD/$path"; fi;
  if [ -z "$PWD" ] || [ ! ${PWD:0:1} = "/" ]; then
    LogOnErr "normalizePath: bash not propely initialized"; onErrorInFunction
  fi
  local changemade=1
  while [ $changemade -ne 0 ]; do
    changemade=0
    realpath=""
    token=
    for token in ${path//\// }
    do
      case $token in
      ""|".") # noop
        ;;
      "..") # up one directory
        changemade=1
        realpath=$(dirname $realpath)
        ;;
      *)
        if [ -h $realpath/$token ]; then
          changemade=1 
          target=`readlink $realpath/$token`
          if [ "${target:0:1}" = '/' ]; then
            realpath=$target
          else
            realpath="$realpath/$target"
          fi
        else
          realpath="$realpath/$token"
        fi
        ;;
      esac
    done
    path=$realpath
  done
  eval $pathvn=\$realpath
  LogIfErr "normalizePath: cannot return mormalized path: $realpath"; ifErrorInFunction
}

enable_NotifyOnStop() {
  common_notifyOnStop=Y
}

enable_NotifyOnAbort() {
  common_notifyOnAbort=Y
}

common_onExit() {
  local exit_status=${1:-$?}
  local procname
  if [ "$common_loaded" = "Y" ]; then
    procname=$APPPATH/$PROCNAME
  else
    procname=$0
  fi
  local i
  for((i=0;i<${#common_onExitFunc[*]};i++))
  do
    eval ${common_onExitFunc[$i]} $exit_status
  done
  if [ "$common_STARTSTOPMSG" = "Y" ]; then
    LogStop $exit_status
  fi
#  if [ ! "$exit_status" = "0" ] && [ "$common_PRINTCALLSTACK" = "Y" ]; then
  if [ ! "$exit_status" = "0" ]; then
    common_PrintCallStack
    common_PRINTCALLSTACK="N"
    if [ "$common_notifyOnAbort" = "Y" ]; then
      alertemail "$PROCDESCR exited with RC=$exit_status."
    fi
  elif [ "$common_notifyOnStop" = "Y" ]; then
    supportemail "$PROCDESCR has been completed successfully."
  fi
  exit $exit_status
}

common_Exit() {
  local i
  if [ ! "$common_KEEPTEMPFILE" = "Y" ]; then
    for((i=0;i<${#common_tempFiles[*]};i++))
    do
      if [ ! -z "${common_tempFiles[$i]}" ]; then
        rmTemp ${common_tempFiles[$i]}
        LogIfErr "cannot remove temp file ${common_tempFiles[$i]}"
        common_tempFiles[$i]=""
      fi
    done
  fi
}

trap "common_onExit" EXIT

addOnExitCallBack() {
  common_onExitFunc[${#common_onExitFunc[*]}]=$1
  ExitIfErr "Cannot add on-exit callback \"$1\"."
}

addOnExitCallBack common_Exit

# Usage: sendEmail -t TOADDRS -r FROMADDRS -c CCADDRS -b BCCARRDS [-m|-M] MESSAGE -f FILENAME [ -f FILENAME ... ]
#
sendEmail() {
  local OPTIND=1 OPT OPTARG
  local FROM=$LOGNAME TO="" CC="" BCC="" SUBJ="" MSG MSGFMT="plain" MSGFNAME MSGFILE BASE ZIPFILE DELETEOPT="" i
  local -a FILES TYPES

  while getopts r:t:c:b:s:f:z:Z:m:M:D OPT
  do
       case $OPT in
           "r" ) FROM=$OPTARG ;;
           "t" ) if [ ! -z "$TO" ];  then TO="$TO,"; fi; TO="$TO$OPTARG" ;;
           "c" ) if [ ! -z "$CC" ];  then CC="$CC,"; fi; CC="$CC$OPTARG" ;;
           "b" ) if [ ! -z "$BCC" ]; then BCC="$BCC,"; fi; BCC="$BCC$OPTARG" ;;
           "s" ) SUBJ=$OPTARG ;;
           "f" ) FILES[${#FILES[*]}]="$OPTARG"; TYPES[${#TYPES[*]}]="P" ;;
# not implemented yet
#           "z" ) FILES[${#FILES[*]}]="$OPTARG"; TYPES[${#TYPES[*]}]="Z" ;;
           "Z" ) ZIPFILE="$OPTARG" ;;
           "D" ) DELETEOPT=" -m" ;;
           "m" ) MSG="$OPTARG"; MSGFMT="plain"; MSGFNAME=message.txt ;;
           "M" ) MSG="$OPTARG"; MSGFMT="html"; MSGFNAME=message.html ;;
            *  ) LogOnErr "sendEmail: unknown option $OPT"; onErrorInFunction ;;
       esac
  done
  shift $(($OPTIND-1))

  if [ -z "$FROM" ]; then
    FROM=$LOGNAME
  fi

  # if requested redirect all emails to
  if [ ! -z "$common_EMAILADDR" ]; then
    TO=$common_EMAILADDR;
    CC="";
    BCC="";
  fi

  for F in $FILES $BASE64 $UUE
  do
     if [ ! -r $F ]; then LogOnErr "sendEmail: Error: File $F does not exist / is not readable."; onErrorInFunction; fi
  done

  if [ -z "$SUBJ" ]; then
    SUBJ="Not specified"
  fi

  mkTemp MSGFILE
  LogIfErr "sendEmail: cannot make MSGFILE temp file"; ifErrorInFunction
  if [ -f $MSGFILE ]; then
    LogOnErr "sendEmail: $MSGFILE temp file already exists"; onErrorInFunction
  fi

  if [ ${#FILES[*]} -eq 0 ] && [ "$MSGFMT" = "plain" ]; then
    echo "\
From: $FROM
To: $TO
Cc: $CC
Bcc: $BCC
Subject: $SUBJ
MIME-Version: 1.0
Content-Type: text/plain

$MSG" >$MSGFILE
  else
    echo "\
From: $FROM
To: $TO
Cc: $CC
Bcc: $BCC
Subject: $SUBJ
MIME-Version: 1.0
Content-Type: multipart/mixed;
	boundary="_a69f9832-94dc-417e-8dbc-1922188d5c28_"

This is a Mime message, which your mail program may not understand. Parts
of the message will appear as text. If the remainder appears as random
characters in the message body, instead of as attachments, then you'll
have to extract these parts and decode them manually.

--_a69f9832-94dc-417e-8dbc-1922188d5c28_
Content-Type: multipart/alternative;
	boundary="_c1143c93-a3d5-49a2-9b66-d1da8f2d2de6_"

--_c1143c93-a3d5-49a2-9b66-d1da8f2d2de6_
Content-Type: text/$MSGFMT; charset="utf-8"
Content-Transfer-Encoding: base64

" >$MSGFILE

    echo "$MSG" | perl -e 'use MIME::Base64 qw(encode_base64);use Encode qw(encode_utf8);local($/) = undef;print encode_base64(<STDIN>);' >>$MSGFILE

    echo "\

--_c1143c93-a3d5-49a2-9b66-d1da8f2d2de6_--" >>$MSGFILE
    LogIfErr "sendEmail: cannot write email header"; ifErrorInFunction

    if [ -z "$ZIPFILE" ]; then
      for(( i=0; i < ${#FILES[*]}; i++ ))
      do
        BaseName BASE ${FILES[$i]}
        echo --_a69f9832-94dc-417e-8dbc-1922188d5c28_  >>$MSGFILE
        echo Content-Type: application/octet-stream\; name=\"$BASE\">>$MSGFILE
        echo Content-Disposition: attachment\; filename=\"$BASE\">>$MSGFILE
        echo Content-Transfer-Encoding: base64>>$MSGFILE
        echo>>$MSGFILE
        perl -e 'use MIME::Base64 qw(encode_base64);use Encode qw(encode_utf8);local($/) = undef;print encode_base64(<STDIN>);' < ${FILES[$i]} >>$MSGFILE
        LogIfErr "sendEmail: cannot encode $BASE"; ifErrorInFunction
      done
      echo "--_a69f9832-94dc-417e-8dbc-1922188d5c28_--" >>$MSGFILE
    else
      mkTemp FULLZIP
      LogIfErr "sendEmail: cannot make FULLZIP temp file"; ifErrorInFunction
      execCMD -l 1 zip -j -q$DELETEOPT -D $FULLZIP ${FILES[*]}
      LogIfErr "sendEmail: cannot zip attachemts to $ZIPFILE"; ifErrorInFunction
      echo --_a69f9832-94dc-417e-8dbc-1922188d5c28_  >>$MSGFILE
      echo Content-Type: application/octet-stream\; name=\"$ZIPFILE\">>$MSGFILE
      echo Content-Disposition: attachment\; filename=\"$ZIPFILE\">>$MSGFILE
      echo Content-Transfer-Encoding: base64>>$MSGFILE
      echo>>$MSGFILE
      perl -e 'use MIME::Base64 qw(encode_base64);use Encode qw(encode_utf8);local($/) = undef;print encode_base64(<STDIN>);' < $FULLZIP >>$MSGFILE
      LogIfErr "sendEmail: cannot encode $ZIPFILE"; ifErrorInFunction
      echo "--_a69f9832-94dc-417e-8dbc-1922188d5c28_--" >>$MSGFILE
      rmTemp $FULLZIP
    fi
  fi
  cat $MSGFILE | /usr/lib/sendmail -t -f $FROM
  LogIfErr "sendEmail: cannot send email"; ifErrorInFunction
  rmTemp $MSGFILE
}

sendemail() {
 local emailto="$1"
 local subject="$2"
 shift; shift
 if [ -z "$emailto" ]; then
   Log "email to is not specified"
 fi
 sendEmail -t "$emailto" -s "$MACHINENAME($PROCNAME): $subject" -m "$*"
}

alertemail() {
 local subject="$1";
 shift
 Log "ALERT: \"$subject\" sent to $ALERTEMAIL"
 sendemail "$ALERTEMAIL" "$subject" "$*"
}

supportemail() {
 local subject="$1";
 shift
 Log "INFO: \"$subject\" sent to $SUPPORTEMAIL"
 sendemail "$SUPPORTEMAIL" "$subject" "$*"
}

import() {
  local inc; local inloadedvar
  local common_abc="^[a-z|A-Z|_][a-z|A-Z|_|0-9|\\.]*$"
  for inc in $*
  do
    if [[ ! "$inc" =~ $common_abc ]]; then
      Err "wrong module name to import($inc)"
    fi
    incloadedvar="common_loaded_${inc}"
    if [ ! "${!incloadedvar}" = "Y" ]; then
      if [ -f $APPROOT/bin/${inc}.func ]; then
        if [ -f $APPROOT/conf/${inc}.conf ]; then
          set -e
          . $APPROOT/conf/${inc}.conf
          set +e
        fi
        set -e
        . $APPROOT/bin/${inc}.func
        set +e
        LogIfErr "cannot import ${inc}.func"; ifErrorInFunction
      elif [ -f $APPPATH/bin/${inc}.func ]; then
        if [ -f $APPPATH/conf/${inc}.conf ]; then
          set -e
          . $APPPATH/conf/${inc}.conf
          set +e
        fi
        set -e
        . $APPPATH/bin/${inc}.func
        set +e
        LogIfErr "cannot load ${inc}.func"; ifErrorInFunction
      else
        Err "cannot find ${inc}.func in $APPROOT/bin/ and $APPPATH/bin/."
      fi
      LogIfErr "cannot find ${inc}.func"; ifErrorInFunction
      eval $incloadedvar="Y"
      LogIfErr "cannot set $incloadedvar flag"; ifErrorInFunction
    fi
  done
}

# usage: execCMD [-d processname] [-l log level] [-E] command
# -d processname - process name
# -l loglevel    - log level
# -E             - stop on error
# -N             - return on error with return code 1
# -R             - variable to return output result
common_STOPONERROR=Y
execCMDstopOnError() {
  common_STOPONERROR=Y
}
execCMDreturnOnError() {
  common_STOPONERROR=N
}
execCMD() {
  local OPT OPTIND OPTARG DESCR STOPONERROR=$common_STOPONERROR RC OUTPUTFILE loglevel=0 OUTPUT RESULTVNAME
  while getopts d:l:ENR: OPT
  do
    case $OPT in
      "d" ) DESCR="$OPTARG" ;;
      "l" ) loglevel="$OPTARG" ;;
      "E" ) STOPONERROR="Y" ;;
      "N" ) STOPONERROR="N" ;;
      "R" ) RESULTVNAME="$OPTARG" ;;
       *  ) LogOnErr "execCMD: execCMD: wrong opttion $OPT"; onErrorInFunction ;;
    esac
  done
  shift $(($OPTIND-1))
  if [ -z "$DESCR" ]; then DESCR="$@"; fi
  Log -l $loglevel -n "start: $DESCR..."
  mkTemp OUTPUTFILE
  RC=0
  "$@" >$OUTPUTFILE 2>&1
  RC=$?
  OUTPUT="$(<$OUTPUTFILE)"
  LogIfErr "execCMD: completed with error: $OUTPUT"; ifErrorInFunction;
  Write -l $loglevel "ok"
  if [ ! -z "$RESULTVNAME" ]; then
    eval $RESULTVNAME=\$OUTPUT
  fi
  rmTemp $OUTPUTFILE
  return $RC
}

common_TEMPID=0
common_tempFilesCN=0
common_tempFilesCNSavePoint=0

unset common_tempFiles common_tempFilesCNs
declare -a common_tempFiles common_tempFilesCNs

# usage: mkTemp FILEVARNAME EXT
mkTemp() {
  local tempname common_varName=$1
  local -i i newTempID=-1
  for((i=0;i<$common_TEMPID;i++)); do
    if [ -z "${common_tempFiles[$i]}" ]; then
      newTempID=$i
      break;
    fi
  done

  if [ $newTempID -lt 0 ]; then
    newTempID=$common_TEMPID
    common_TEMPID=$(($common_TEMPID+1))
  fi
  common_tempFilesCN=$(($common_tempFilesCN+1))

  tempname=`mktemp -u -p $TMPDIR $common_varName.$SCRIPTNAME.\`date +%s\`.$$.$newTempID.XXXXXXXXXX`
  LogIfErr "mkTemp: cannot make temp file"; ifErrorInFunction
  if [ -z "$tempname" ]; then
    Log "mkTemp: temp file is emapty"; onErrorInFunction
  fi

  if [ ! -z "$2" ]; then
    tempname=$tempname.$2
  fi
  eval $common_varName=\$tempname
  LogIfErr "mkTemp: cannot return temp file name to $common_varName"; ifErrorInFunction

  common_tempFiles[$newTempID]=$tempname
  LogIfErr "mkTemp: cannot record temp file name in array"; ifErrorInFunction
  common_tempFilesCNs[$newTempID]=$common_tempFilesCN
}

setTempPoint() {
  common_tempFilesCNPoint=$common_tempFilesCN
}

clearToTempPoint() {

  local i

  if [ common_tempFilesCNPoint -gt 0 ]; then
    for((i=0;i<${#common_tempFiles[*]};i++))
    do
      if [ ${common_tempFilesCN[$i]} -gt $common_tempFilesCNPoint ]; then
        rmTemp ${common_tempFiles[$i]}
        LogIfErr "clearToTempPoint: cannot remove \"${common_tempFiles[$i]}\" temp file"; ifErrorInFunction
      fi
    done
    common_tempFilesCNPoint=0
  fi
}

# usage: mkRemoteTemp FILEVARNAME
mkRemoteTemp() {
  local tempname

  tempname="/tmp/tmp.$MACHINENAME.$SCRIPTNAME.`date +%s`.$$.$common_TEMPID"
  LogIfErr "mkRemoteTemp: cannot make temp file"; ifErrorInFunction

  if [ -z "$tempname" ]; then
    Log "mkRemoteTemp: temp file is emapty"; onErrorInFunction
  fi

  common_TEMPID=$(($common_TEMPID+1))
  eval $1=\$tempname
  LogIfErr "mkRemoteTemp: cannot return temp file name to $1"; ifErrorInFunction
}

# usage: rmTemp FILENAME
rmTemp() {
  local tempname i
  tempname=$1
  if [ -z "$tempname" ]; then
    LogOnErr "rmTemp: temp file name is emapty"; onErrorInFunction
  fi
  for((i=0;i<$common_TEMPID;i++))
  do
    if [ "${common_tempFiles[$i]}" = "$tempname" ]; then
      rm -f $tempname
      LogIfErr "cannot remove temp file: $tempname"; ifErrorInFunction
      common_tempFiles[$i]=""
      common_tempFilesCN[$i]=0
      if [ $i -eq $(($common_TEMPID-1)) ]; then
        common_TEMPID=$(($common_TEMPID-1))
      fi
      return 0
    fi
  done
  Log -l 1 "cannot find temp file to remove: $tempname"; onErrorInFunction
}

renameTemp() {
  local tempname filename i
  tempname=$1
  filename=$2
  if [ -z "$tempname" ] || [ -z "$filename" ]; then
    OnErrorInFunction "rmTemp: temp or destination file name is emapty"
  fi
  for((i=0;i<${#common_tempFiles[*]};i++))
  do
    if [ "${common_tempFiles[$i]}" = "$tempname" ]; then
      mv $tempname $filename
      LogIfErr "cannot rename $tempname file to $filename"; ifErrorInFunction
      common_tempFiles[$i]=""
      return 0
    fi
  done
  Log -l 1 "cannot find temp file to rename: $tempname"; onErrorInFunction
}

# Split [-m maxfields|-M maxfields] -n minfields -d STR -a ARERAYNAME LINE
Split() {
  local LINE; local LINE1; local LINE2;
  local OPT; local OPTIND; local OPTARG;
  local delimiter aname i anamelen
  local maxfields; local minfields; local maxtype
  while getopts d:n:m:a:M: OPT
  do
    case $OPT in
      "d" ) delimiter="$OPTARG" ;;
      "a" ) aname="$OPTARG" ;;
      "n" ) minfields="$OPTARG" ;;
  "m"|"M" ) maxfields="$OPTARG"; maxtype="$OPT" ;;
       *  ) LogIfErr "Split: unknown option $OPT"; ifErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  if [ -z "$delimiter" ] || [ -z "$aname" ]; then
    LogIfErr "Split: delimiter or array name are not specified"; ifErrorInFunction
  fi
  shift $(($OPTIND-1))
  LINE="$*"
  LINE1=$LINE
#  for((i=0;;i++))
#  do
#    eval anamelen=\${#$aname[*]}
#    if [ $anamelen -eq 0 ]; then break; fi
#    eval unset $aname[$i]
#    LogIfErr "Split: cannot make $aname array empty. make sure local or declare command was used with -a option"; ifErrorInFunction;
#  done
  eval anamelen=\${#$aname[*]}
  LogIfErr "Split: cannot get length of $aname array"; ifErrorInFunction;
  if [ $anamelen -ne 0 ]; then LogOnErr "Split: destination array $aname is not empty"; onErrorInFunction; fi
  if [ ! -z "$maxfields" ]; then
    #let maxfields--;
    maxfields=$(($maxfields-1))
  fi
  if [ ! -z "$minfields" ]; then
    #let minfields--;
    minfields=$(($minfields-1))
  fi
  if [ ! -z "$LINE1" ]; then
    for((i=0;;i++))
    do
      LINE2=${LINE1#*$delimiter}
      if [ "$LINE1" = "$LINE2" ]; then
        eval $aname[$i]=\${LINE1}
        break;
      elif [ ! -z "$maxfields" ] && [ $i -ge $maxfields ]; then
        if [ "$maxtype" = "M" ]; then
          eval $aname[$i]=\${LINE1}
        else
          eval $aname[$i]=\${LINE1:0:$((${#LINE1}-${#LINE2}-1))}
        fi
        break;
      else
        eval $aname[$i]=\${LINE1:0:$((${#LINE1}-${#LINE2}-1))}
        LogIfErr "Split: cannot return value: $aname[$i]=\${LINE1:0:$((${#LINE1}-${#LINE2}-1))}"; ifErrorInFunction;
      fi
      LINE1=$LINE2
    done
  else
    i=-1
  fi
  if [ ! -z "$minfields" ] && [ $i -lt $minfields ]; then
    LogOnErr "Split: minimum number of fields ( $(($minfields+1)) ) violated : $LINE"; onErrorInFunction;
  fi
}

# Replace SRINGVARNAME SUBSTRING REPLACE
Replace() {
  local strvname=$1 substr=$2 replstr=$3 L strv
  strv=${!strvname}
  LogIfErr "Replace: cannot get string"; ifErrorInFunction;
  L=${strv//$substr/$replstr}
  LogIfErr "Replace: cannot replace substring"; ifErrorInFunction;
  eval $strvname=\$L
  LogIfErr "Replace: cannot reurn string"; ifErrorInFunction;
}

toUpper() {
  local retn=$1 retv curv=$2
  retv=`echo "$curv" | tr [:lower:] [:upper:] 2>&1`
  LogIfErr "cannot uppercase: $retv"; ifErrorInFunction
  eval $retn=\$retv
  LogIfErr "cannot return uppercased"; ifErrorInFunction
}
toLower() {
  local retn=$1 retv curv=$2
  retv=`echo "$curv" | tr [:upper:] [:lower:] 2>&1`
  LogIfErr "cannot uppercase: $retv"; ifErrorInFunction
  eval $retn=\$retv
  LogIfErr "cannot return lowercased"; ifErrorInFunction
}

# Instr IDXVARNAME STRING SUBSTRING
Instr() {
  local str=$2 substr=$3 idxvn=$1 L sublen
  sublen=${#substr}
  substr=${substr//\\/\\\\}
  substr=${substr//\$/\\\$}
  substr=${substr//\`/\\\`}
  L=${str#*$substr}
  if [ "$L" = "$str" ]; then
    eval $idxvn=-1
  else
    #eval let $idxvn=${#str}-${#L}-${sublen}
    eval $idxvn=$((${#str}-${#L}-${sublen}))
  fi
  LogIfErr "Instr: cannot return string"; ifErrorInFunction;
}

# usage readFile [-m maxfields|-M maxfields] -n minfields -d STR [-a ARERAYNAMEPREFIX | -A ARRAY0 [-A ARRAY1]...] FILENAME
readFile() {
  local L;
  local -a arr; local -a arrlist; local -a sarr; local -a sparam
  local OPT; local OPTIND; local OPTARG;
  local nrow delimiter anameprefix i maxfields maxtype filename;
  local splitargs skipcomments skipempty;
  local tmp_NUMREGEXP="^[0-9]*$"
  local tmp_MmREGEXP='^M|m$'

  while getopts d:n:m:a:M:A:S:ce OPT
  do
    case $OPT in
      "d" ) delimiter="$OPTARG" ;;
      "c" ) skipcomments="Y" ;;
      "e" ) skipempty="Y" ;;
      "a" ) anameprefix="$OPTARG" ;;
      "A" ) arrlist[${#arrlist[*]}]="$OPTARG" ;;
      "S" )
        Split -d "=" -n 2 -m 2 -a sparam "$OPTARG"
        LogIfErr "readFile: cannot parse filter $OPTARG, RC=$?"; ifErrorInFunction
        if [ ! -z "${sparam[0]}" ] && [[ "${sparam[0]}" =~ $tmp_NUMREGTEXP ]]; then
          sarr[${sparam[0]}]=${sparam[1]}
        else  
          LogOnErr "readFile: cannot parse filter $OPTARG, sparam[0]=${sparam[0]}"; onErrorInFunction
        fi
        ;;
      "n" ) splitargs="$splitargs -n $OPTARG" ;;
  "m"|"M" ) splitargs="$splitargs -$OPT $OPTARG"; maxtype=$OPT; maxfields="$OPTARG" ;;
       *  ) LogOnErr "readFile: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done

  shift $(($OPTIND-1))
  filename=$1
  if [ -z "$delimiter" ]; then
    delimiter=":"
  fi
  if [ -z "$anameprefix" ] && [ ${#arrlist[*]} -eq 0 ]; then
    LogOnErr "readFile: array prefix or list of arrays were not defined"; onErrorInFunction
  fi
  if [ $# -ne 1 ] || [ -z "$filename" ]; then
    LogOnErr "readFile: finename is required"; onErrorInFunction
  fi
  if [ ! -f $filename ]; then
    LogOnErr "readFile: file $filename not found"; onErrorInFunction
  fi
  if [ ! -z "$anameprefix" ] && [ ! -z "$arrlist" ]; then
    LogOnErr "readFile: -a and -A options are mutualy exclusive"; onErrorInFunction
  fi
  if [ ${#arrlist[*]} -ne 0 ] && ( [[ ! "$maxtype" =~ $tmp_MmREGEXP ]] || [ ${#arrlist[*]} -lt $maxfields ] ); then
    LogOnErr "readFile: -A option requires -M with sufficien number of array names"; onErrorInFunction
  fi
  nrow=0
  if [ -z "$delimiter" ]; then delimiter='	'; fi
  while read -r L;
  do
    if ! ( [ "$skipcomments" = "Y" ] && [ "${L:0:1}" = "#" ] ) && ! ( [ "$skipempty" = "Y" ] && [ ${#L} -eq 0 ] ); then
      unset arr
      local -a arr
      Split -d "$delimiter" $splitargs -a arr "$L"
      LogIfErr "readFile: cannot split line"; ifErrorInFunction
      for((i=0;i<${#arr[*]};i++))
      do
        if [ ! -z "${sarr[$i]}" ] && [[ ! "${arr[$i]}" =~ ${sarr[$i]} ]]; then
          continue 2
        fi
      done
      for((i=0;i<${#arr[*]};i++))
      do
        if [ ! -z "$anameprefix" ]; then
          eval ${anameprefix}_$i[$nrow]=\${arr[$i]}
        else
          eval ${arrlist[$i]}[$nrow]=\${arr[$i]}
        fi
        LogIfErr "readFile: cannot assign value to element of array"; ifErrorInFunction
      done
      #let nrow++
      nrow=$(($nrow+1))
    fi
  done < $filename
}

# usage readFile [-n minfields] -m maxfields [-d STR] [-a ARERAYNAMEPREFIX | -A ARRAY0 [-A ARRAY1]...] FILENAME

readData() {

  local OPT OPTIND OPTARG;
  local delimiter skipcomments skipempty anameprefix arrays filename RC
  local MINFIELDS=0 MAXFIELDS i j
  local -a arrlist

  while getopts d:n:m:a:M:A:ce OPT
  do
    case $OPT in
      "d" ) delimiter="$OPTARG" ;;
      "c" ) skipcomments=1 ;;
      "e" ) skipempty=1 ;;
      "a" ) anameprefix="$OPTARG" ;;
      "A" ) arrlist[${#arrlist[*]}]="$OPTARG"; if [ ! -z "$arrays" ]; then arrays="$arrays,"; fi; arrays="$arrays$OPTARG" ;;
      "n" ) MINFIELDS=$OPTARG; ;;
      "m" ) MAXFIELDS=$OPTARG; ;;
       *  ) LogOnErr "readFile: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done

  shift $(($OPTIND-1))
  filename=$1
  if [ -z "$delimiter" ]; then  delimiter="	"; fi
  if [ -z "$anameprefix" ] && [ ${#arrlist[*]} -eq 0 ]; then
    LogOnErr "readFile: both array prefix and list of arrays were not defined"; onErrorInFunction
  fi
  if [ ! -z "$anameprefix" ] && [ ${#arrlist[*]} -ne 0 ]; then
    LogOnErr "readFile: -a and -A options are mutualy exclusive"; onErrorInFunction
  fi
  if [ -z "$MAXFIELDS" ]; then
    LogOnErr "readFile: -m pararameter is required"; onErrorInFunction
  fi
  if [ -z "$filename" ] || [ ! -f $filename ]; then
    LogOnErr "readFile: file \"$filename\" not found"; onErrorInFunction
  fi
  if [ ${#arrlist[*]} -ne 0 ] && [ ${#arrlist[*]} -ne $MAXFIELDS ]; then
    LogOnErr "readFile: -A option requires -M with sufficien number of array names"; onErrorInFunction
  fi
  if [ ! -z "$anameprefix" ]; then
    for((i=0;i<$MAXFIELDS;i++)); do
      if [ ! -z "$arrays" ]; then arrays="$arrays,"; fi; arrays="$arrays$anameprefix$i"
    done
  fi

  local initScript=$TMPDIR/initArray.$$.tmp

  mkTemp errOutput
  LogIfErr "readFile: cannot make errOutput temp file"; ifErrorInFunction
  awk -v dolar='$' \
      -v fileID=$fileID \
      -v ARRAYS=$arrays \
      -v SKIPCOMMENTS=$skipcomments \
      -v SKIPEMPTY=$skipempty \
      -v MINFIELDS=$MINFIELDS \
      -v MAXFIELDS=$MAXFIELDS \
      -v DELIMITER="$delimiter" \
  '\
function unescape(b) {
  a=""; incomplete=0;
/*print "original b:" b "<";*/
  for(;;) {
    sidx = index( b, "\\" );
    if( sidx == 0 || sidx >= length(b) ) {
      if( match( substr( b, length( b ), 1 ), "^\\\\$" ) ) incomplete=1;
/*print "substr( b, " length( b ) ", 1 ): " substr( b, length( b ), 1 );*/
/*print "b:" b "<";*/
/*print "incomplete result: " incomplete;*/
      a = a b;
      break;
    }
    c = substr( b, sidx+1, 1 );
    a = a substr( b, 1, sidx - 1 ) c;
    b = substr( b, sidx + 2 );
  }
  return a;
} BEGIN { narr = split( ARRAYS, AN, "," ); aIdx=0; /*incomplete=0;*/ }
{
  aIdx++;
  if( ! ( SKIPCOMMENTS == 1 && match( $0, "^#" ) ) && ! ( SKIPEMPTY == 1 && match( $0, "^$" ) ) )
  {
    icur=0;
    delete AR;
    delete AV;
    ncur=split( $0, AV, DELIMITER );
/*    for( n=1; n <= ncur; n++ ) AV[n] = unescape( AV[n] );*/
/*print "ncur=" ncur;*/
    for( i=1; i<=ncur; i++ ) {
      icur++;
/*      AR[icur] = AV[i];*/
      AR[icur] = unescape( AV[i] );
/*print "AR[" icur "]=" AR[icur];*/
/*print "incomplete: " incomplete; */
/*      while( match( AR[icur], "\\\\$" )  ) {*/
      while( incomplete == 1  ) {
        i++;
        JOINCHAR=DELIMITER;
/*print "incomplete1: " incomplete;*/
        if( i > ncur ) {
          {
            prevNR=NR
            getline
            if( NR != prevNR+1 ) {
              print "unexpected end of file: NR=" NR ", PNR=" prevNR ", NF=" NF ", FNR=" FNR ", aIdx=" aIdx ", NR=" NR > "/dev/stderr";
              exit 4;
            }
          } while ( ( SKIPCOMMENTS == 1 && match( $0, "^#" ) ) || ( SKIPEMPTY == 1 && match( $0, "^$" ) ) );
          JOINCHAR="\n";
          delete AV;
          ncur=split( $0, AV, DELIMITER );
/*          for( n=1; n <= ncur; n++ ) AV[n] = unescape( AV[n] );*/
          i=1;
        }
/*        AR[icur]=substr( AR[icur], 1, length(AR[icur])-1 ) JOINCHAR AV[i];*/
        AR[icur]=substr( AR[icur], 1, length(AR[icur])-1 ) JOINCHAR unescape( AV[i] );
      }
    }
    if( icur > narr ) {
      print "unexpected field found: i=" i ", ncur=" ncur ", icur=" icur ", aIdx=" aIdx ", NR=" NR > "/dev/stderr";
      exit 3;
    }
    nfields=icur;
    if( nfields < MINFIELDS || nfields > MAXFIELDS ) {
      print "insufficient number of fields: FOUND=" nfields ", required between " MINFIELDS " and " MAXFIELDS ", aIdx=" aIdx ", NR=" NR > "/dev/stderr";
      exit 1;
    }
    for( i=1; i <= narr; i++ ) {
      gsub( /\\/,"\\\\", AR[i] ); gsub( "\"", "\\\"", AR[i] ); gsub( "\\$", "\\$", AR[i] ); gsub( "`", "\\`", AR[i] );
      printf( "%s[%s]=\"%s\"\n", AN[i], aIdx-1, ( i <= nfields ? AR[i] : "" ) );
    }
  }
}' $filename >$initScript 2>$errOutput
  RC=$?
  if [ $RC -ne 0 ]; then
    LogOnErr "readFile: cannot prepare init array script from $filename (RC=$RC): $(<$errOutput)"; rmTemp $errOutput; onErrorInFunction
  fi
  rmTemp $errOutput
  LogIfErr "readFile: cannot remove errOutput temp file"; ifErrorInFunction
#Write -n "loading..."
  set -e
  . $initScript
  set +e
  rm $initScript
  LogIfErr "readFile: cannot remove $initScript init file"; ifErrorInFunction
}

# usage readParametersFile -p parameter -v varname [ [ -p parameter -v varname ] ... ] FILENAME
readParametersFile() {
  local -a parr varr pman fnam fval
  local OPT OPTIND OPTARG i j
  while getopts P:p:v: OPT
  do
    case $OPT in
      "P" ) parr[${#parr[*]}]="$OPTARG"; pman[${#pman[*]}]="Y" ;;
      "p" ) parr[${#parr[*]}]="$OPTARG"; pman[${#pman[*]}]="N" ;;
      "v" ) varr[${#varr[*]}]="$OPTARG" ;;
       *  ) LogOnErr "readParametersFile: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  filename=$1
  if [ ${#parr[*]} -eq 0 ] || [ ${#parr[*]} -ne ${#varr[*]} ] || [ -z "$filename" ]; then
    LogOnErr "readParametersFile: wrong parameters $*"; onErrorInFunction;
  fi
  for((i=0;i<${#varr[*]};i++))
  do
    eval ${varr[$i]}=""
  done
  readFile -c -e -d "=" -M 2 -A fnam -A fval $filename
  for((i=0;i<${#parr[*]};i++)); do
    for((j=0;j<${#fnam[*]};j++)); do
      if [ "${parr[$i]}" = "${fnam[$j]}" ]; then
        eval ${varr[$i]}=\${fval[$j]}
        continue 2
      fi
    done
    if [ "${pman[$i]}" = "Y" ]; then
      LogOnErr "readParametersFile: mandatory parameter ${parr[$i]} cannot be found in file $filename"; onErrorInFunction;
    fi
  done
}

# usage BaseName BNAMEVARNAME PATH EXT
BaseName() {
  local vn; local path; local ext
  local tmp_extREGEXP=".*$ext\$"
  vn=$1; path=$2; ext=$3
  path=${path##*/}
  if [ ! -z "$ext" ]; then
    if [[ "$path" =~ $tmp_extREGEXP ]]; then
      path=${path%$ext}
      LogIfErr "BaseName: cannot delete extention"; ifErrorInFunction
    fi
  fi
  eval $vn=\$path
  LogIfErr "BaseName: cannot return basename"; ifErrorInFunction
}

# usage: DirName DNAMEVAR PATH
DirName() {
  local vn; local path; local path1
  vn=$1; path=$2;
  if [ -z "$path" ]; then
    LogIfErr "DirName: path is empty"; ifErrorInFunction
  fi
  path1=${path%/*}
  if [ "$path" = "$path1" ]; then
    path="."
  elif [ -z "$path1" ]; then
    path="/"
  else
    path=$path1
  fi
  eval $vn=\$path
  LogIfErr "DirName: cannot return dirname"; ifErrorInFunction
}

# usage: arrayAppend targetArray arrayToAppend
arrayAppend() {
  local targetArrayName="$1" arrayToAppendName="$2" NTO NFROM i
  eval NTO=\${#$targetArrayName[*]}
  eval NFROM=\${#$arrayToAppendName[*]}
  LogIfErr "arrayAppend: cannot get length of target array ($targetArrayName), RC=$?"; ifErrorInFunction
  for((i=0;i<$NFROM;i++)); do
    eval $targetArrayName[$NTO]=\${$arrayToAppendName[$i]}
    LogIfErr "arrayAppend: cannot append element to target array ($targetArrayName), RC=$?"; ifErrorInFunction
    #let NTO++
    NTO=$(($NTO+1))
  done
}

# usage: arrayDelete
arrayDelete() {
  local aname="$1" anamelen
  for((i=0;;i++))
  do
    eval anamelen=\${#$aname[*]}
    if [ $anamelen -eq 0 ]; then break; fi
    eval unset $aname[$i]
    LogIfErr "arrayDelete: cannot make $aname array empty. make sure local or declare command was used with -a option"; ifErrorInFunction;
  done
}

# usage: arrayDeleteElement
arrayDeleteElement() {
  local aname="$1" elnum="$2" anamelen
  eval anamelen=\${#$aname[*]}
  if [ $anamelen -gt $elnum ]; then
    for((i=$elnum;i<$anamelen-1;i++))
    do
      eval $aname[$i]=\${$aname[$(($i+1))]}
      LogIfErr "arrayDeleteElement: cannot reassign $i element in $aname array ($anamelen)"; ifErrorInFunction;
    done
    eval unset $aname[$(($anamelen-1))]
    LogIfErr "arrayDeleteElement: cannot delete last element from $aname array ($anamelen)"; ifErrorInFunction;
    return
  fi
  LogOnErr "arrayDeleteElement: element with id $elnum is not in $aname array ($anamelen)"; ifErrorInFunction;
}

# usage: arrayGetElementIdx ARRAYNAME VALUE IDXVARNAME
arrayGetElementIdx() {
  local aname="$1" elval="$2" elidxname="$3" anamelen val i
  eval anamelen=\${#$aname[*]}
  for((i=0;i<$anamelen;i++))
  do
    eval val=\${$aname[$i]}
    if [ "$val" = "$elval" ]; then
      eval $elidxname=\$i
      LogIfErr "arrayGetElementIdx: cannot return index (i) to $elidxname"; ifErrorInFunction;
      return
    fi
  done
  eval $elidxname=-1
  LogIfErr "arrayGetElementIdx: cannot return -1 $elidxname"; ifErrorInFunction;
}

# usage: startTimer TIMERVAR
startTimer() {
  local tiTimer; local tiTimerVar=$1
  tiTimer=`date +%s.%N`
  tiTimer=${tiTimer:0:${#tiTimer}-3}
  eval $tiTimerVar=\$tiTimer
}

# usage: readTimer TIMERVAR TIMEDIFFVAR
readTimer() {
  local tiTimer; local tiTimerVar=$1; local tiDeltaVar=$2; local tiTimerDelta; local tiStartTimer
  eval tiStartTimer=\${$tiTimerVar}
  tiTimer=`date +%s.%N`
  tiTimer=${tiTimer:0:${#tiTimer}-3}
  tiTimerDelta=`echo $tiStartTimer $tiTimer|awk '{print $2-$1}'`
  eval $tiTimerVar=\$tiTimer
  eval $tiDeltaVar=\$tiTimerDelta
}

common_TOTALIDLETIME=0
common_WAKEUPREQ="N"

Sleep() {
 local start=$SECONDS i sleep_interval
 if [ -z "$2" ]; then
   sleep_interval=1
 else
   sleep_interval=$2
 fi
 for((i=0;i<$1;i=i+$sleep_interval)); do
   sleep $sleep_interval;
   if [ "$common_WAKEUPREQ" = "Y" ]; then common_WAKEUPREQ="N"; break; fi
 done;
 common_TOTALIDLETIME=$(($common_TOTALIDLETIME+$SECONDS-$start))
}

inicfg_NUMFILE=0
inicfgParseFile() {
  local fileID line fileName
  local OPTIND=1 OPT OPTARG
  while getopts s:f: OPT
  do
    case $OPT in
      "f" ) fileID="${OPTARG}";;
       *  ) LogOnErr "inicfgParseFile: unknown option: $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  fileName=$1;
  if [ -z "$fileID" ] || [ -z "$fileName" ]; then
    LogOnErr "inicfgParseFile: file_id or filename is empty"; onErrorInFunction
  fi
  local initScript=$TMPDIR/initVars.$$.tmp
  local initScript=$TMPDIR/initVars.$SCRIPTNAME.$inicfg_NUMFILE.$$.tmp
  cat $fileName | tr -d "\r" | sed -e '/^#/d;' | awk -v dolar='$' -v fileID=$fileID 'BEGIN {inSection=0;sectionsNum=-1}
  {
    if( match( $0, "^\\[.*\\]$") == 1 ) {
      if( inSection==1 ) printf( "%s=%s\n", fileID "_attrNum_" sectionsNum, attrsNum );
      sectionsNum++;
      sectionName=substr( $0, 2, length($0)-2 );
      gsub( /\\/,"\\\\",sectionName); gsub( "\"", "\\\"", sectionName ); gsub( "\\$", "\\$", sectionName ); gsub( "`", "\\`", sectionName );
      printf( "%s[%d]=\"%s\"\n", fileID "_sectionsList", sectionsNum, sectionName );
      inSection=1;
      attrsNum=0;
    } else {
      if( inSection == 1 ) {
        eqPos = index( $0, "=" );
        if( eqPos > 0 ) {
          attrName=substr( $0, 1, eqPos-1 );
          gsub( /\\/,"\\\\",attrName); gsub( "\"", "\\\"", attrName ); gsub( "\\$", "\\$", attrName ); gsub( "`", "\\`", attrName );
          printf( "%s[%d]=\"%s\"\n", fileID "_attrName_" sectionsNum, attrsNum, attrName );
          val=substr( $0, eqPos+1 );
          if( index( val, "<<" ) == 1 ) {
            EOFLINE=substr( val, 3 );
            if( length( EOFLINE ) == 0 ) { exit 3; }
            val=""
            for(;;) {
              getline line;
              if( length( EOFLINE ) == length( line ) && index( line, EOFLINE ) == 1 ) break;
              val = val ( length(val) > 0 ? "\n" : "" ) line;
            }
            EOFLINE="";
          } else {
            while( match( substr( val, length(val), 1 ), "^\\\\$" ) == 1 ) {
              getline line;
              val = substr( val, 1, length(val) - 1 ) line;
            }
          }
          gsub( /\\/,"\\\\",val); gsub( "\"", "\\\"", val ); gsub( "\\$", "\\$", val ); gsub( "`", "\\`", val );
          printf( "%s[%d]=\"%s\"\n", fileID "_attrVals_" sectionsNum, attrsNum, val );
          attrsNum++;
        } else {
          if ( length( $0 ) > 0 ) {
            exit 1;
          }
        }
      } else {
        exit 2;
      }
    }
  } END {
    if( length( EOFLINE ) > 0 ) exit 5;
    printf( "%s=%s\n", fileID "_attrNum_" sectionsNum, attrsNum );
    sectionsNum++;
    printf( "%s=%s\n", fileID "_sectionsNum", sectionsNum );
  }' >$initScript
  LogIfErr "inicfgParseFile: cannot parse config file: $fileName"; ifErrorInFunction
  set -e
  . $initScript
  set +e
  LogIfErr "inicfgParseFile: cannot initialize config file: $fileName"; ifErrorInFunction
  inicfg_NUMFILE=$(($inicfg_NUMFILE+1))
  rm $initScript
}

inicfgCloseFile() {
  local fileID secsNum attrsNum i j k
  local OPTIND=1 OPT OPTARG
  while getopts f: OPT
  do
    case $OPT in
      "f" ) fileID="${OPTARG}";;
       *  ) LogOnErr "inicfgParseFile: unknown option: $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  if [ -z "$fileID" ]; then
    LogOnErr "inicfgCloseFile: fileID is empty"; onErrorInFunction
  fi
  eval secsNum=\$${fileID}_sectionsNum
  if [ $? -ge 0 ] && [ ! -z "$secsNum" ] && [ $secsNum -gt 0 ]; then
    for((i=0;i<$secsNum;i++))
    do
      eval unset ${fileID}_attrName_$i
      LogIfErr "inicfgCloseFile: cannot unset ${fileID}_attrName_$i"; ifErrorInFunction
      eval unset ${fileID}_attrVals_$i
      LogIfErr "inicfgCloseFile: cannot unset ${fileID}_attrVals_$i"; ifErrorInFunction
      eval unset ${fileID}_attrNum_$i
      LogIfErr "inicfgCloseFile: cannot unset ${fileID}_attrNum_$i"; ifErrorInFunction
    done
    eval unset ${fileID}_sectionsList
    LogIfErr "inicfgCloseFile: cannot unset ${fileID}_sectionsList"; ifErrorInFunction
    eval unset ${fileID}_sectionsList
    LogIfErr "inicfgCloseFile: cannot unset ${fileID}_sectionsList"; ifErrorInFunction
    eval unset ${fileID}_sectionsNum
    LogIfErr "inicfgCloseFile: cannot unset ${fileID}_sectionsNum"; ifErrorInFunction
  else
    LogOnErr "inicfgCloseFile: cannot get sectionsNum from ${fileID}_sectionsNum"; onErrorInFunction
  fi
}

inicfgWriteFile() {
  local fileID secsNum attrsNum i j k overwrite filename v tempfile
  local OPTIND=1 OPT OPTARG
  while getopts of: OPT
  do
    case $OPT in
      "o" ) overwrite=Y;;
      "f" ) fileID="${OPTARG}";;
       *  ) LogOnErr "inicfgWriteFile: unknown option: $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  filename=$1;
  if [ -z "$fileID" ]; then
    LogOnErr "inicfgWriteFile: fileID is empty"; onErrorInFunction
  fi
  if [ -z "$filename" ]; then
    LogOnErr "inicfgWriteFile: filename is empty"; onErrorInFunction
  fi
  if [ ! "$overwrite" = "Y" ] && [ -f $fileName ]; then
    LogOnErr "inicfgWriteFile: $filename already exists"; onErrorInFunction
  fi
  mkTemp tempfile
  eval secsNum=\$${fileID}_sectionsNum
  if [ $? -ge 0 ] && [ ! -z "$secsNum" ] && [ $secsNum -gt 0 ]; then
    for((i=0;i<$secsNum;i++))
    do
      if [ $i -gt 0 ]; then
        eval echo >> $tempfile
      fi
      eval echo \"[\${${fileID}_sectionsList[$i]}]\" >> $tempfile
      LogIfErr "inicfgWriteFile: cannot write sectionname"; ifErrorInFunction
      eval attrsNum=\$${fileID}_attrNum_$i
      if [ $? -ge 0 ] && [ ! -z "$attrsNum" ] && [ $attrsNum -ge 0 ]; then
        for((j=0;j<$attrsNum;j++))
        do
          eval v=\${${fileID}_attrVals_$i[$j]}
          LogIfErr "inicfgWriteFile: cannot get attr value"; ifErrorInFunction
          eval echo \"\${${fileID}_attrName_$i[$j]}=\$v\" >> $tempfile
          LogIfErr "inicfgWriteFile: cannot write sectionname"; ifErrorInFunction
          if [ ! -z "$v" ] && [ "${v:${#v}-1}" = '\' ]; then
            LogOnErr "inicfgWriteFile: continue line character is not supported at the end of value: $v"; onErrorInFunction
          fi
        done
      else
        LogOnErr "inicfgWriteFile: cannot get attrsNum from ${fileID}_attrNum_$i"; onErrorInFunction
      fi
    done
    eval echo \$${fileID}_sectionsList
    LogIfErr "inicfgWriteFile: cannot unset ${fileID}_sectionsList"; ifErrorInFunction
    eval echo \$${fileID}_sectionsNum
    LogIfErr "inicfgWriteFile: cannot unset ${fileID}_sectionsNum"; ifErrorInFunction
  else
    LogOnErr "inicfgWriteFile: cannot get sectionsNum from ${fileID}_sectionsNum"; onErrorInFunction
  fi
  execCMD "rm -f $filename"
  renameTemp $tempfile $filename
}

inicfgIsInitialized() {
  local fileID secsNum secsNumVar
  local OPTIND=1 OPT OPTARG
  while getopts of: OPT
  do
    case $OPT in
      "o" ) overwrite=Y;;
      "f" ) fileID="${OPTARG}";;
       *  ) LogOnErr "inicfgWriteFile: unknown option: $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  if [ -z "$fileID" ]; then
    LogIfErr "inicfgIsInitialized: ${fileID} is empy"; ifErrorInFunction
  fi
  secsNumVar=${fileID}_sectionsNum
  secsNum={!secsNumVar}
  LogIfErr "inicfgIsInitialized: cannot get secsNum"; ifErrorInFunction
  if [ -z "$secsNum" ]; then
    return 1
  fi
}

inicfgGetSectionId() {
  local fileID secName i secNumVar SectionIdVarName NOTFOUND="Y"
  local OPTIND=1 OPT OPTARG
  while getopts s:f:N OPT
  do
    case $OPT in
      "s" ) secName="${OPTARG}";;
      "f" ) fileID="${OPTARG}";;
      "N" ) NOTFOUND="N";;
       *  ) LogOnErr "inicfgGetSectionId: unknown option: ${OPT}"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  SectionIdVarName=$1
  #
  secNumVar=${fileID}_sectionsNum
  if [ -z "${!secNumVar}" ] || [ ! ${!secNumVar} -gt 0 ]; then
    LogOnErr "inicfgGetSectionId: ${fileID}_sectionsNum has not been initialized."; onErrorInFunction
  fi
  local secListVar=${fileID}_sectionsList
  for((i=0;i<${!secNumVar};i++))
  do
    local elvar=${secListVar}[$i]
    local elval="${!elvar}"
    if [ "$secName" = "$elval" ] && [ ! -z "$secName" ]; then
      eval $SectionIdVarName=\$i
      LogIfErr "inicfgGetSectionId: cannot return value"; ifErrorInFunction
      return
    fi
  done
  if [ "$NOTFOUND" = "N" ]; then
    eval $SectionIdVarName=-1
    LogIfErr "inicfgGetSectionId: cannot return -1"; ifErrorInFunction
  else
    LogOnErr "inicfgGetSectionId: cannot find section $secName"; onErrorInFunction
  fi
}

inicfgGetAttrNum() {
  local fileID secName attNumVar attNumVar attNumVal AttrNumVarName
  local OPTIND=1 OPT OPTARG
  while getopts s:S:f: OPT
  do
    case $OPT in
      "s" ) secName="${OPTARG}";;
      "S" ) secId="${OPTARG}";;
      "f" ) fileID="${OPTARG}";;
       *  ) LogOnErr "inicfgGetAttrNum: unknown option: ${OPT}"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  AttrNumVarName=$1
  #
  if [ ! -z "$secName" ]; then
    inicfgGetSectionId -f ${fileID} -s ${secName} secId
    LogIfErr "inicfgGetAttrNum: cannot get section ID"; ifErrorInFunction
  fi
  #
  attNumVar=${fileID}_attrNum_$secId
  attNumVal="${!attNumVar}"
  if [ -z "$attNumVal" ]; then
    LogOnErr "inicfgGetAttrNum: attNumVal is empty"; onErrorInFunction
  fi
  eval $AttrNumVarName=\$attNumVal
  LogIfErr "inicfgGetAttrNum: cannot return value"; ifErrorInFunction
}

inicfgGetSectionsNum() {
  local fileID secNumVar secNumVal SectionsNumVarName
  local OPTIND=1 OPT OPTARG
  while getopts f: OPT
  do
    case $OPT in
      "f" ) fileID="${OPTARG}";;
       *  ) LogOnErr "inicfgGetSectionsNum: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  SectionsNumVarName=$1
  secNumVar=${fileID}_sectionsNum
  secNumVal=${!secNumVar}
  if [ -z "$secNumVal" ] || [ ! $secNumVal -gt 0 ]; then
    LogOnErr "inicfgGetSectionsNum: problem with secNumVal"; onErrorInFunction
  fi
  eval $SectionsNumVarName=\$secNumVal
  LogIfErr "inicfgGetSectionsNum: cannot return value"; ifErrorInFunction
}

inicfgGetAttrId() {
  local fileID secName attName attNumVar attNumVar i AttrIdVarName NOTFOUND="Y"
  local OPTIND=1 OPT OPTARG
  while getopts S:a:f:N OPT
  do
    case $OPT in
      "S" ) secId="${OPTARG}";;
      "a" ) attName="${OPTARG}";;
      "f" ) fileID="${OPTARG}";;
      "N" ) NOTFOUND="N";;
       *  ) LogOnErr "inicfgGetAttrId: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  AttrIdVarName=$1
  #
  attNumVar=${fileID}_attrNum_$secId
#  if [ -z ${!attNumVar} ] || [ ${!attNumVar} -eq 0 ]; then
  if [ -z ${!attNumVar} ] || [ ${!attNumVar} -lt 0 ]; then
    LogOnErr "inicfgGetAttrId: ${fileID}_attrNum_$secId has not been initialized."; onErrorInFunction
  fi
  for((i=0;i<${!attNumVar};i++))
  do
    local elvar=${fileID}_attrName_${secId}[$i]
    local elval="${!elvar}"
    if [ "$elval" = "$attName" ]; then
      eval $AttrIdVarName=\$i
      LogIfErr "inicfgGetAttrId: cannot return value"; ifErrorInFunction
      return
    fi
  done
  if [ "$NOTFOUND" = "N" ]; then
    eval $AttrIdVarName=-1
    LogIfErr "inicfgGetAttrId: cannot return -1"; ifErrorInFunction
  else
    LogOnErr "inicfgGetAttrId: cannot find attribute $attName"; onErrorInFunction
  fi
}

inicfgGetAttrName() {
  local OPTIND=1 OPT OPTARG
  local elvar elval NOTFOUNDOPT
  local secName secId attId fileID AttrNameVarName
  while getopts s:S:A:f: OPT
  do
    case $OPT in
      "s" ) secName="${OPTARG}";;
      "S" ) secId="${OPTARG}";;
      "A" ) attId="${OPTARG}";;
      "f" ) fileID="${OPTARG}";;
       *  ) LogOnErr "inicfgGetAttrName: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  AttrNameVarName=$1
  if ( [ -z "$secName" ] && [ -z "$secId" ] ) || [ -z "$attId" ]; then
    LogOnErr "inicfgGetAttrName: incorrect parameters"; onErrorInFunction
   fi
  if [ ! -z "$secName" ]; then
    inicfgGetSectionId -f ${fileID} -s ${secName} secId
    LogIfErr "inicfgGetAttrName: cannot find get sectionId for ${secName}"; ifErrorInFunction
  fi
  elvar=${fileID}_attrName_${secId}[$attId]
  elval="${!elvar}"
  LogIfErr "inicfgGetAttrName: cannot get attribute name from $elvar"; ifErrorInFunction
  eval $AttrNameVarName=\$elval
  LogIfErr "inicfgGetAttrName: cannot return value"; ifErrorInFunction
}

inicfgGetAttrValue() {
  local OPTIND=1 OPT OPTARG
  local elvar elval NOTFOUNDOPT
  local secName secId attName attId fileID AttrValueVarName defaultVarName incfgPsw
  while getopts s:a:S:A:d:f:N OPT
  do
    case $OPT in
      "s" ) secName="${OPTARG}";;
      "S" ) secId="${OPTARG}";;
      "a" ) attName="${OPTARG}";;
      "A" ) attId="${OPTARG}";;
      "d" ) defaultVarName="${OPTARG}";;
      "N" ) NOTFOUNDOPT="-N";;
      "f" ) fileID="${OPTARG}";;
       *  ) LogOnErr "inicfgGetAttrValue: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  if [ ! -z "$defaultVarName" ]; then NOTFOUNDOPT="-N"; fi
  AttrValueVarName=$1
  if ( [ -z "$secName" ] && [ -z "$secId" ] ) || ( [ -z "$attName" ] && [ -z "$attId" ] ); then
    LogOnErr "inicfgGetAttrValue: incorrect parameters"; onErrorInFunction
   fi
  if [ ! -z "$secName" ]; then
    inicfgGetSectionId -f ${fileID} -s ${secName} secId
    LogIfErr "inicfgGetAttrValue: cannot find get sectionId for ${secName}"; ifErrorInFunction
  fi
  if [ ! -z "$attName" ]; then
    inicfgGetAttrId -f ${fileID} -S ${secId} -a "$attName" $NOTFOUNDOPT attId
    LogIfErr "inicfgGetAttrValue: cannot find get attributeId for $attName"; ifErrorInFunction
  fi
  if [ $attId -lt 0 ]; then
    if [ ! -z "$defaultVarName" ]; then
      eval $AttrValueVarName=\$defaultVarName
    else
      eval $AttrValueVarName=""
    fi
  else
    elvar=${fileID}_attrVals_${secId}[$attId]
    elval="${!elvar}"
    LogIfErr "inicfgGetAttrValue: cannot get attribute value from $elvar"; ifErrorInFunction
    if [ "${elval:0:4}" = "enc:" ]; then
      elval=`echo ${elval:4} | ~/bin/pwenc dec`
      LogIfErr "inicfgGetAttrValue: cannot decrypt value"; ifErrorInFunction
    else
      if [ "${elval:0:6}" = "plain:" ]; then
        elval=${elval:6}
      fi
    fi
    eval $AttrValueVarName=\$elval
  fi
  LogIfErr "inicfgGetAttrValue: cannot return value"; ifErrorInFunction
}

inicfgGetAttrValueAsArray() {
  local OPTIND=1; local OPT; local OPTARG
  local elvar; local elval
  local secNameOpt secIdOpt attNameOpt attIdOpt fileIDOpt AttrValuesArrName val delimiter NOTFOUNDOPT
  while getopts s:a:S:A:f:d:N OPT
  do
    case $OPT in
      "s" ) secNameOpt="-s ${OPTARG}";;
      "S" ) secIdOpt="-S ${OPTARG}";;
      "a" ) attNameOpt="-a ${OPTARG}";;
      "A" ) attIdOpt="-A ${OPTARG}";;
      "N" ) NOTFOUNDOPT="-N";;
      "f" ) fileIDOpt="-f ${OPTARG}";;
      "d" ) delimiter="${OPTARG}";;
       *  ) LogOnErr "inicfgGetAttrValue: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  AttrValuesArrName=$1
  inicfgGetAttrValue $secNameOpt $secIdOpt $attNameOpt $attIdOpt $fileIDOpt $NOTFOUNDOPT val
  LogIfErr "inicfgGetAttrValueAsArray: get attribute value"; ifErrorInFunction
  if [ -z "$delimiter" ]; then
    delimiter=","
  fi
  Split -d $delimiter -a $AttrValuesArrName "$val"
  LogIfErr "inicfgGetAttrValueAsArray: cannot split value: $val"; ifErrorInFunction
}

inicfgGetSectionsList() {
  local secName secExpr attType attNum=0 attVal i j numFound=0 attrNum
  local -a attName attExpr
  local SectionsListVarName listName secNumVar secListVar expr secID
  local OPTIND=1 OPT OPTARG
  while getopts s:a:f:e: OPT
  do
    case $OPT in
      "s" ) secExpr="$OPTARG" ;;
      "a" ) attName[${#attName}]="${OPTARG}" ;;
      "e" ) attExpr[${#attExpr}]="${OPTARG}" ;;
      "f" ) fileID="${OPTARG}" ;;
       *  ) LogOnErr "inicfgGetSectionsList: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  SectionsListVarName=$1
  listName=${fileID}_sectionsList
  secNumVar=${fileID}_sectionsNum
  secListVar=${fileID}_sectionsList
  if [ ${#attName[*]} -ne ${#attExpr[*]} ]; then
    LogOnErr "inicfgGetSectionsList: diff numbers of attributes and expressins (${#attName} ${#attExpr})"; onErrorInFunction
  fi
  #
  if [ -z "${!secNumVar}" ] || [ ! ${!secNumVar} -gt 0 ]; then
    LogOnErr "inicfgGetSectionsList: wrong secNumVar"; onErrorInFunction
  fi
  for((i=0;i<${!secNumVar};i++)); do
    local elvar=${secListVar}[$i]
    local secName="${!elvar}"
    if [ -z "$secName" ]; then LogOnErr "inicfgGetSectionsList: secName is empty"; onErrorInFunction; fi
#Log "secName: $secName"
#Log "secExpr: $secExpr"
    if [[ "$secName" =~ $secExpr ]]; then
#Log "secName =~ secExpr"
      if [ "${#attName[*]}" -eq 0 ]; then
#        echo "$secName"
        eval $SectionsListVarName[$numFound]=\$secName
        LogIfErr "cannot return section name to $SectionsListVarName[$numFound]"; ifErrorInFunction
        numFound=$(($numFound+1))
      else
        inicfgGetSectionId -f $fileID -s $secName secID
        LogIfErr "inicfgGetSectionsList: cannot get section id for $secName"; ifErrorInFunction
        for((j=0;j<${#attName[*]};j++)); do
          inicfgGetAttrValue -f $fileID -S $secID -a ${attName[$j]} attVal
          LogIfErr "inicfgGetSectionsList: cannot get attr value for $secID:${attName[$j]}"; ifErrorInFunction
          if [[ ! "$attVal" =~ ${attExpr[$j]} ]]; then
            continue 2
          fi
        done
        eval $SectionsListVarName[$numFound]=\$secName
        LogIfErr "inicfgGetSectionsList: cannot return value to $SectionsListVarName[$numFound]"; ifErrorInFunction
        numFound=$(($numFound+1))
      fi
    fi
  done
}

inicfgGetAttrsList() {
  local secId secType attType aName attVal i j attName attrsNum numFound=0
#  local -a  attExpr
  local AttrsListVarName listName secNumVar secListVar expr secID
  local OPTIND=1 OPT OPTARG
  while getopts S:a:f: OPT
  do
    case $OPT in
      "S" ) secID="$OPTARG" ;;
      "a" ) attName="${OPTARG}" ;;
#      "a" ) attName[${#attName}]="${OPTARG}" ;;
#      "e" ) attExpr[${#attExpr}]="${OPTARG}" ;;
      "f" ) fileID="${OPTARG}" ;;
       *  ) LogOnErr "inicfgGetAttrsList: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  AttrsListVarName=$1
  eval numFound=\${#${AttrsListVarName}[*]}
  if [ $numFound -ne 0 ]; then
    LogOnErr "inicfgGetAttrsList: $AttrsListVarName is not empty"; onErrorInFunction
  fi
  #
  inicfgGetAttrNum -f $fileID -S $secID attrsNum
  for((i=0;i<${attrsNum};i++))
  do
    eval aName=\${${fileID}_attrName_${secId}[$i]}
    if [[ "$aName" =~ ${attName} ]]; then
      eval $AttrsListVarName[$numFound]=\$aName
      LogIfErr "inicfgGetAttrsList: cannot return value"; ifErrorInFunction
      #let numFound++
      numFound=$(($numFound+1))
    fi
  done
}

inicfgAddAttr() {
  local fileID secName secId attName attId i secNumVar SectionIdVarName AttrValue updateiffound
  local OPTIND=1 OPT OPTARG
  while getopts s:a:S:f:U OPT
  do
    case $OPT in
      "s" ) secName="${OPTARG}";;
      "S" ) secId="${OPTARG}";;
      "a" ) attName="${OPTARG}";;
      "U" ) updateiffound="Y";;
      "f" ) fileID="${OPTARG}";;
       *  ) LogOnErr "inicfgAddAttr: unknown option $OPT"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  AttrValue="$@"
  if [ ! -z "$secName" ]; then
    inicfgGetSectionId -s "$secName" -f $fileID secId
  fi
  inicfgGetAttrId -N -S "$secId" -a "$attName" -f $fileID attId
  LogIfErr "inicfgAddAttr: cannot check attr"; ifErrorInFunction
  if [ $attId -eq -1 ]; then
    inicfgGetAttrNum -S "$secId" -f $fileID attId
    LogIfErr "inicfgAddAttr: cannot get number of attributes"; ifErrorInFunction
    eval ${fileID}_attrName_$secId[$attId]=\$attName
    LogIfErr "inicfgAddAttr: cannot assign name to new attr"; ifErrorInFunction
    eval ${fileID}_attrVals_$secId[$attId]=\$AttrValue
    LogIfErr "inicfgAddAttr: cannot assign value to new attr"; ifErrorInFunction
    eval ${fileID}_attrNum_$secId=$(($attId+1))
    LogIfErr "inicfgAddAttr: cannot increase counter"; ifErrorInFunction
  elif [ $attId -ge 0 ] && [ "$updateiffound" = "Y" ]; then
    eval ${fileID}_attrVals_$secId[$attId]=\$AttrValue
    LogIfErr "inicfgAddAttr: cannot assign value to new attr"; ifErrorInFunction
  else
    LogOnErr "inicfgAddAttr: attribute $attName already exist in sectin wit hID $secId"; onErrorInFunction
  fi
}

inicfgSetAttr() {
  inicfgAddAttr -U "$@"
}

inicfgGetSectionName() {
  local fileID secName secID i secNumVar SectionNameVarName secListVar
  local OPTIND=1 OPT OPTARG
  while getopts S:f:N OPT
  do
    case $OPT in
      "S" ) secID="${OPTARG}";;
      "f" ) fileID="${OPTARG}";;
       *  ) LogOnErr "inicfgGetSectionName: unknown option: ${OPT}"; onErrorInFunction ;;
    esac
    OPTIND=$OPTIND
  done
  shift $(($OPTIND-1))
  SectionNameVarName=$1
  #
  secNumVar=${fileID}_sectionsNum
  if [ -z "${!secNumVar}" ] || [ ! ${!secNumVar} -gt 0 ] || [ $secID -ge ${!secNumVar} ]; then
    LogOnErr "inicfgGetSectionName: ${fileID}_sectionsNum error."; onErrorInFunction
  fi
  local secListVar=${fileID}_sectionsList[$secID]
  secName=${!secListVar}

  eval $SectionNameVarName=\$secName
  LogIfErr "inicfgGetSectionName: cannot return value to $SectionNameVarName"; ifErrorInFunction
}

# Usage: svnExport svnpath filepath svnuser svnpassword
svnExport() {

  local svnpath=$1 filepath=$2 tempfile
  local svnuser=$3 svnpass=$4

  if [ -z "$filepath" ]; then
    LogOnErr "export path has not been defined"; onErrorInFunction
  fi

  mkTemp tempfile
  LogIfErr "cannot make temp file"; ifErrorInFunction

  svn export -q --username "$svnuser" --password "$svnpass" --no-auth-cache --non-interactive $svnpath $tempfile
  LogIfErr "cannot export file from $svnpath"; ifErrorInFunction

  if [ ! -f $tempfile ]; then
    LogOnErr "cannot export file from $svnpath"; onErrorInFunction
  fi

  mv -f $tempfile $filepath
  LogIfErr "cannot rename temp file to $filepath"; ifErrorInFunction

}

dateAddMinutes() {

  local local_datevar=$1
  local local_curdate=$2
  local local_minutes=$3
  local local_newdate

  if [ -z "$3" ]; then
    LogOnErr "dateAddMinutes: wrong aprameters"; onErrorInFunction
  fi

  local_newdate=`date "+%Y%m%d %H%M" -d "$local_minutes minutes ${local_curdate:0:8} ${local_curdate:8:4}"`
  LogIfErr "cannot add $local_minutes to $local_curdate date"; ifErrorInFunction

  eval $local_datevar=\"\${local_newdate:0:8}\${local_newdate:9:4}\"
  LogIfErr "cannot return new date ($local_newdate) to $local_datevar variable"; ifErrorInFunction
}


##!includefile=<common.paths>
BaseName PROCNAME $0
BaseName SCRIPTNAME $0 .sh
DirName APPPATH $0
normalizePath APPPATH
#DirName APPROOT ${BASH_SOURCE[0]}
APPROOT=$APPPATH
#normalizePath APPROOT
LOGDIR=.
CONFDIR=$APPPATH
TMPDIR=/tmp
LOGFILENAME=""
LCKFILE=$LOGDIR/$SCRIPTNAME.lck
MACHINENAME=`hostname`
PROCDESCR="$PROCNAME($SCRIPTNAME)"

##!includefile=<common.appprops>

if [ -f $APPROOT/params.conf ]; then
  . $APPROOT/params.conf
  ExitIfErr "cannot load $APPROOT/params.conf"
else
usage() {
  echo
  echo "usage $0 [options] args"
  echo
  exit 1
}
fi

if [ -f $APPROOT/$SCRIPTNAME.func ]; then
  . $APPROOT/$SCRIPTNAME.func
  ExitIfErr "cannot execute $SCRIPTNAME.func. exiting."
fi

if [ -f $APPROOT/params.conf ]; then
  . $APPROOT/params.conf
  ExitIfErr "cannot load $APPROOT/params.conf."
fi

if [ -f $APPROOT/$SCRIPTNAME.conf ]; then
  . $APPROOT/$SCRIPTNAME.conf
  ExitIfErr "cannot load $APPROOT/$SCRIPTNAME.conf."
fi


if [ ${#common_opt_var_name[*]} -gt 0 ] && [ ${#common_par_var_name[*]} -gt 0 ]; then

#unset common_Params
#declare -a common_Params

common_int_var_name=([0]="common_LOGLEVEL" [1]="common_CONSOLEOUTPUT" [2]="common_KEEPTEMPFILE" [3]="common_EMAILADDR" [4]="common_HELPONLY" [5]="common_PRINTCALLSTACK")
common_int_shortopt=([0]="" [1]="" [2]="" [3]="" [4]="" [5]="")
common_int_long_opt=([0]="log-level" [1]="console-output" [2]="keep-tempfiles" [3]="redirect-to" [4]="help" [5]="print-call-stack")
common_int_with_val=([0]="Y" [1]="N" [2]="N" [3]="Y" [4]="N" [5]="N")
common_int_required=([0]="N" [1]="N" [2]="N" [3]="N" [4]="N" [5]="N")
common_int_opt_type=([0]="i" [1]="b" [2]="b" [3]="t" [4]="b" [5]="b")
common_int_opt_hide=([0]="N" [1]="N" [2]="Y" [3]="Y" [4]="N" [5]="Y")
common_int_checkval=([0]="" [1]="" [2]="" [3]="" [4]="" [5]="")
common_int_mismatch=([0]="" [1]="" [2]="" [3]="" [4]="" [5]="")
common_int_describe=(\
[0]="allows the debug level (logging level) to be specified" \
[1]="allows/disallows console output" \
[2]="allows/disallows temp files removal" \
[3]="redirect all emails to specified address" \
[4]="give this help list" \
[5]="print call stack on error")

common_initParams() {
  local optind; local i; local j; local etntry_type;
  local LINE; local OPTFILE;
  local -a ALINE
  local split;
  local tmp_bBREGEXP="^[b|B]$"
  common_optNum=0
  common_parNum=0
  if [ ${#common_opt_var_name[*]} -eq 0 ] && [ ${#common_par_var_name[*]} -eq 0 ] ; then
    for OPTFILE in $APPPATH/conf/$SCRIPTNAME.options
    do
       while read -r LINE
       do
         if [ ! -z "$LINE" ] && [ ! "${LINE:0:1}" = '#' ]; then
           unset ALINE
           local -a ALINE
           Split -M 10 -d ":" -a ALINE "$LINE"
           etntry_type=${ALINE[0]}
           if [ "$etntry_type" = 'O' ] || [ "$etntry_type" = 'o' ]; then
             common_opt_var_name[$common_optNum]=${ALINE[1]}
             common_opt_shortopt[$common_optNum]=${ALINE[2]}
             common_opt_long_opt[$common_optNum]=${ALINE[3]}
             common_opt_with_val[$common_optNum]=${ALINE[4]}
             common_opt_required[$common_optNum]=${ALINE[5]}
             common_opt_opt_type[$common_optNum]=${ALINE[6]}
             common_opt_checkval[$common_optNum]=${ALINE[7]}
             common_opt_mismatch[$common_optNum]=${ALINE[8]}
             common_opt_describe[$common_optNum]=${ALINE[9]}
             #
             if [ ! "${common_opt_with_val[$common_optNum]}" = "Y" ] && [[ ! "${common_opt_opt_type[$common_optNum]}" =~ $tmp_bBREGEXP ]];
             then
               Err "option without value should have boolean type: $LINE"
             fi
             if ( [ "${common_opt_opt_type[$common_optNum]}" = "b" ] || [ "${common_opt_opt_type[$common_optNum]}" = "B" ] ) &&
                [ "${common_opt_with_val[$common_optNum]}" = "Y" ]
             then
               Err "boolean option with value: $LINE"
             fi
             if [ "$etntry_type" = 'o' ]; then
               common_opt_opt_hide[$common_optNum]='Y';
             fi
             #let common_optNum++
             common_optNum=$(($common_optNum+1))
           elif [ "$etntry_type" = 'P' ]; then
             common_par_var_name[$common_parNum]=${ALINE[1]}
             common_par_required[$common_parNum]=${ALINE[5]}
             common_par_opt_type[$common_parNum]=${ALINE[6]}
             common_par_checkval[$common_parNum]=${ALINE[7]}
             common_par_describe[$common_parNum]=${ALINE[9]}
             #let common_parNum++
             common_parNum=$(($common_parNum+1))
           else
             Err "unknow entry type in $APPPATH/conf/$SCRIPTNAME.options: $etntry_type"
           fi
         fi
       done < $OPTFILE
    done
  else
    common_optNum=${#common_opt_var_name[*]}
    common_parNum=${#common_par_var_name[*]}
  fi
  for((i=0;i<${#common_int_var_name[*]};i++))
  do
    common_opt_var_name[$common_optNum]=${common_int_var_name[$i]}
    common_opt_shortopt[$common_optNum]=${common_int_shortopt[$i]}
    common_opt_long_opt[$common_optNum]=${common_int_long_opt[$i]}
    common_opt_with_val[$common_optNum]=${common_int_with_val[$i]}
    common_opt_required[$common_optNum]=${common_int_required[$i]}
    common_opt_opt_type[$common_optNum]=${common_int_opt_type[$i]}
    common_opt_opt_hide[$common_optNum]=${common_int_opt_hide[$i]}
    common_opt_checkval[$common_optNum]=${common_int_checkval[$i]}
    common_opt_mismatch[$common_optNum]=${common_int_mismatch[$i]}
    common_opt_describe[$common_optNum]=${common_int_describe[$i]}
    #let common_optNum++
    common_optNum=$(($common_optNum+1))
  done
}

# common_checkValue [B|b|I|i|F|f|T|t] Name CheckExpr Value
common_checkValue() {

  local tmp_NUMREGEXP="^[0-9]*$"
  local tmp_FLOAT1REGEXP="^[0-9]*\.$"
  local tmp_FLOAT2REGEXP="^[0-9]*\.[0-9]*$"

  if [ "$1" = "B" ] || [ "$1" = "b" ]; then
    if [ ! "$4" = "Y" ] && [ ! "$4" = "N" ]; then
      UsageAndExit "wrong value for boolean option $2: $4";
    fi
  elif [ "$1" = "I" ] || [ "$1" = "i" ]; then
    if [[ ! "$4" =~ $tmp_NUMREGEXP ]];
      then UsageAndExit "wrong value for integer option $2: $4";
    fi
  elif [ "$1" = "F" ] || [ "$1" = "f" ]; then
    if [[ ! "$4" =~ $tmp_FLOAT1REGEXP ]] && [[ ! "$4" =~ $tmp_FLOAT2REGEXP ]] && [[ ! "$4" =~ $tmp_NUMREGEXP ]] ; then
      UsageAndExit "wrong value for float option $2: $4";
    fi
  elif [ ! "$1" = "T" ] && [ ! "$1" = "t" ]; then
    UsageAndExit "Unknown option type for $2: $1"
  fi
  if [ ! -z "$3" ]; then
    if [[ ! "$4" =~ $3 ]]; then
      UsageAndExit "Incorrect value for option $2: \"$4\""
    fi
  fi
}

common_parseParams() {
  local pnum; local nparams; local i; local j; local param; local pn; local pv; local aParamsName; local pnumnext np
  local defopt=$1
  local tmp_SPACEREGEXP=' '
  local tmp_bBEGEXP="^[b|B]$"
  local tmp_BTFIREGEXP='^[B|T|F|I]$'
  shift
  nparams=$#
  pnum=0
  for((i=1;i<=$nparams;i++));
  do
    #let np=$i-1
    np=$(($i-1))
    eval param=\$\{$i\}
if [ "$defopt" = "N" ]; then
    if [ ! -z "$common_COMMANDLINEPARAMS" ]; then common_COMMANDLINEPARAMS="$common_COMMANDLINEPARAMS "; fi
    if [[ "$param" =~ $tmp_SPACEREGEXP ]]; then
      common_COMMANDLINEPARAMS="$common_COMMANDLINEPARAMS\"$param\""
    else
      common_COMMANDLINEPARAMS=$common_COMMANDLINEPARAMS$param
    fi
fi
    if [ "${param:0:1}" = "-" ]; then
      if [ "${param:0:2}" = "--" ]; then
        pv=${param#--*=}
        if [ -z "$pv" ]; then
          UsageAndExit "empty value found: $param"
        elif [ "$pv" = "$param" ]; then # no equal sign
          pn="${param:2}"
          pv=""
        else
          pn=${param:2:$((${#param}-${#pv}-3))}
        fi
        if [ -z "$pn" ]; then
          UsageAndExit "empty option has been supplied"
        fi
        #
        for((j=0;j<$common_optNum;j++));
        do
          if [ "${common_opt_long_opt[$j]}" = "$pn" ]; then
            if [ "${common_opt_opt_type[$j]}" = "b" ]; then
              if [ "$pv" = "Y" ] || [ "$pv" = "y" ] || [ "$pv" = "true" ] || [ "$pv" = "TRUE" ]; then
                pv="Y"
              elif [ "$pv" = "N" ] || [ "$pv" = "n" ] || [ "$pv" = "false" ] || [ "$pv" = "FALSE" ]; then
                pv="N"
              else
                UsageAndExit "wrong value for long form boolean option $pn found: $pv"
              fi
            fi
            break;
          elif [[ "${common_opt_opt_type[$j]}" =~ $tmp_bBEGEXP ]] && [ "enable-${common_opt_long_opt[$j]}" = "$pn" ]; then
            if [ ! -z "$pv" ]; then
              UsageAndExit "bololean option with explicit value found: $param"
            fi
            pv="Y"
            break;
          elif [[ "${common_opt_opt_type[$j]}" =~ $tmp_bBEGEXP ]] && [ "disable-${common_opt_long_opt[$j]}" = "$pn" ]; then
            if [ ! -z "$pv" ]; then
              UsageAndExit "bololean option with explicit value found: $param"
            fi
            pv="N"
            break;
          fi
        done
        if [ $j -ge $common_optNum ]; then UsageAndExit "unknown option: $param"; fi
        if [ -z "$pv" ] && [ "${common_opt_required[$j]}" = "Y" ]; then
          UsageAndExit "mandatory value for $param is missed."
        fi
      elif [ ${#param} -eq 2 ]; then
        pn=${param:1}
        for((j=0;j<$common_optNum;j++));
        do
          if [ "${common_opt_shortopt[$j]}" = "$pn" ]; then
            break;
          fi
        done
        if [ $j -ge $common_optNum ]; then UsageAndExit "unknown option: $param"; fi
        if [ "${common_opt_with_val[$j]}" = "Y" ]; then
          #let i++
          i=$(($i+1))
          eval pv=\$\{$i\}
          if [[ "$pv" =~ $tmp_SPACEREGEXP ]]; then
            common_COMMANDLINEPARAMS="$common_COMMANDLINEPARAMS \"$pv\""
          else
            common_COMMANDLINEPARAMS="$common_COMMANDLINEPARAMS $pv"
          fi
        else
          pv="Y"
        fi
      else
        UsageAndExit "short option should be a single character option: $param"
      fi
      #
      common_checkValue "${common_opt_opt_type[$j]}" "${common_opt_var_name[$j]}" "${common_opt_checkval[$j]}" "$pv"
      #
      if [ "${common_opt_optfound[$j]}" = "Y" ] && [ "$defopt" = "Y" ]; then
        continue;
      fi
      if [[ "${common_opt_opt_type[$j]}" =~ $tmp_BTFIREGEXP ]]; then
        local arrlen
        eval arrlen=\${#${common_opt_var_name[$j]}[*]}
        eval ${common_opt_var_name[$j]}[$arrlen]=\$pv
      else
        if [ "${common_opt_optfound[$j]}" = "Y" ]; then
          UsageAndExit "duplicated option found: $param"
        fi
        eval ${common_opt_var_name[$j]}=\$pv
      fi
      ExitIfErr "Cannot assign value to ${common_opt_var_name[$j]}"
      if [ "$defopt" = "Y" ]; then
        common_opt_optfound[$j]="D"
      else
        common_opt_optfound[$j]="Y"
      fi
    else
      if [ $pnum -lt $common_parNum ]; then
        if [[ "${common_par_opt_type[$pnum]}" =~ $tmp_BTFIREGEXP ]]; then
          eval ${common_par_var_name[$pnum]}[\${#${common_par_var_name[$pnum]}[*]}]=\$param
          ExitIfErr "Cannot assign value to parameters array #$pnum"
          common_par_parfound[$pnum]="Y"
          #let pnumnext=pnum
          pnumnext=$pnum
        else
          eval ${common_par_var_name[$pnum]}=\$param
          ExitIfErr "Cannot assign value to parameter #$pnum"
          common_par_parfound[$pnum]="Y"
          #let pnumnext=pnum+1
          pnumnext=$(($pnum+1))
        fi
      else
        UsageAndExit "unexpected parameter #$pnum found."
      fi
      common_checkValue "${common_par_opt_type[$pnum]}" "${common_par_var_name[$pnum]}" "${common_par_checkval[$pnum]}" "$param"
      pnum=$pnumnext
    fi
  done
  if [ "$defopt" = "Y" ]; then
    for((j=0;j<$common_optNum;j++));
    do
      if [ "${common_opt_optfound[$j]}" = "D" ]; then
        common_opt_optfound[$j]="Y"
      fi
    done
  fi
}
common_checkParams() {
  local local i; local j;
  #
  for((j=0;j<$common_optNum;j++));
  do
    if [ "${common_opt_required[$j]}" = "Y" ] && [ ! "${common_opt_optfound[$j]}" = "Y" ]; then
      UsageAndExit "option ${common_opt_shortopt[$j]}|${common_opt_long_opt[$j]} is mandatory."
    fi
  done
  #
  for((j=0;j<$common_parNum;j++));
  do
    if [ "${common_par_required[$j]}" = "Y" ] && [ ! "${common_par_parfound[$j]}" = "Y" ]; then
      UsageAndExit "parameter ${common_par_var_name[$j]} is mandatory."
    fi
  done
}

usage() {
  local i; local str; local shelp; local lhelp; local smax=0; local lmax=0; local lopt; local lempty; local loptvname
  local sempty; local descr; local ustr; local pardescr; local maxpar; local curpar
  local tmp_bBEGEXP="^[b|B]$"

  ustr="\nusage: $PROCNAME"
  for((i=0;i<${#common_opt_required[*]};i++))
  do
    #
    if [ ! -z "${common_opt_shortopt[$i]}" ]; then
      if [ "${common_opt_with_val[$i]}" = "Y" ]; then
        shelp[$i]="-${common_opt_shortopt[$i]} ${common_opt_var_name[$i]}"
      else
        shelp[$i]="-${common_opt_shortopt[$i]}"
      fi
      smax=$((${#shelp[$i]}>$smax?${#shelp[$i]}:$smax))
    fi
    #
    if [ ! -z "${common_opt_long_opt[$i]}" ]; then
      if [[ "${common_opt_opt_type[$i]}" =~ $tmp_bBEGEXP ]]; then
        lhelp[$i]="--${common_opt_long_opt[$i]}=[Y|N]"
      elif [ "${common_opt_with_val[$i]}" = "Y" ]; then
        loptvname=${common_opt_var_name[$i]}
        if [ "${loptvname:0:7}" = "common_" ]; then
          loptvname=${loptvname:7}
        fi
        lhelp[$i]="--${common_opt_long_opt[$i]}=$loptvname"
      else
        lhelp[$i]="--${common_opt_long_opt[$i]}"
      fi
      lmax=$((${#lhelp[$i]}>$lmax?${#lhelp[$i]}:$lmax))
    fi
    lopt=$(($smax==0?2:$smax+2))
    if [ $lmax -gt 0 ] && [ $smax -gt 0 ]; then
      #let lopt=$lopt+1;
      lopt=$(($lopt+1));
    fi
    #let lopt=$lopt+$lmax
    lopt=$(($lopt+$lmax))
    #
    if [ ! -z "${lhelp[$i]}" ] && [ ! -z "${shelp[$i]}" ]; then
      ustr="$ustr [${lhelp[$i]}|${shelp[$i]}]"
    elif [ ! -z "${lhelp[$i]}" ]; then
      ustr="$ustr ${lhelp[$i]}"
    elif [ ! -z "${shelp[$i]}" ]; then
      ustr="$ustr ${shelp[$i]}"
    fi
  done
  #
  maxpar=0
  for((i=0;i<${#common_par_var_name[*]};i++))
  do
    maxpar=$(($maxpar<${#common_par_var_name[$i]}?${#common_par_var_name[$i]}:$maxpar))
  done
  #let maxpar=$maxpar  #+7
  maxpar=$maxpar
  newpar=`printf "%$(($maxpar+11))s"`
  pardescr=""
  for((i=0;i<${#common_par_var_name[*]};i++))
  do
    ustr="$ustr ${common_par_var_name[$i]}"
    descr=${common_par_describe[$i]}
    descr=${descr//\\n/\\n$newpar}
    if [ -z "$pardescr" ]; then
      pardescr="\n\n  where:"
    else
      pardescr="$pardescr        "
    fi
    pardescr="$pardescr `printf \"%-${maxpar}s\" \"${common_par_var_name[$i]}\"`  $descr\n"
  done
  #
  echo -e "$ustr$pardescr"
  echo "OPTIONS: "
  echo
  #
  sempty=`printf "%${smax}s"`
  lempty=`printf "%${lmax}s"`
  newlin=`printf "%$(($lmax+$smax+6))s"`
  for((i=0;i<${#common_opt_required[*]};i++))
  do
if [ ! "${common_opt_opt_hide[$i]}" = "Y" ]; then
    str="  "
    if [ -z "${shelp[$i]}" ]; then
      str=$str$sempty
      if [ $lmax -gt 0 ]; then
        str=$str"  "
      fi
    else
      str=$str"`printf "%-${smax}s" "${shelp[$i]}"`"
      if [ $lmax -gt 0 ]; then
        if [ ! -z "${lhelp[$i]}" ]; then
          str=$str", "
        else
          str=$str"  "
        fi
      fi
    fi
    if [ -z "${lhelp[$i]}" ]; then
      str=$str$lempty
    else
      str=$str"`printf "%-${lmax}s" "${lhelp[$i]}"`"
    fi
    descr=${common_opt_describe[$i]}
    descr=${descr//\\n/\\n$newlin}
    echo -e "$str  ${descr}"
fi
  done
}


  common_initParams "$@"
  ExitIfErr "Cannot initialize parameter parser"

  common_COMMANDLINEPARAMS=""
  common_parseParams N "$@"
  ExitIfErr "Cannot parse command line"

  if [ -f $APPPATH/conf/$SCRIPTNAME.defopts ]; then
    eval common_parseParams Y $(<$APPPATH/conf/$SCRIPTNAME.defopts)
    ExitIfErr "Cannot parse default optinos"
  fi

  if [ "$common_HELPONLY" = "Y" ]; then
    common_CONSOLEOUTPUT="Y"
    common_loaded="Y"
    usage
    exit
  fi

  common_checkParams
  ExitIfErr "Cannot check parameters"

fi

#if [ -f $APPPATH/conf/$SCRIPTNAME.options ]; then
##!includefile=<common.params>
#  ExitIfErr "cannot parse parameters"
#fi

common_loaded="Y"
set +e


